package org.jeecg.common.modules.withdraw.service.impl;

import lombok.extern.slf4j.Slf4j;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.modules.doctor.entity.Doctor;
import org.jeecg.common.modules.doctor.entity.DoctorAccount;
import org.jeecg.common.modules.doctor.entity.DoctorAccountFlow;
import org.jeecg.common.modules.doctor.service.IDoctorAccountFlowService;
import org.jeecg.common.modules.doctor.service.IDoctorAccountService;
import org.jeecg.common.modules.doctor.service.IDoctorService;
import org.jeecg.common.modules.withdraw.entity.WithdrawRecord;
import org.jeecg.common.modules.withdraw.mapper.WithdrawRecordMapper;
import org.jeecg.common.modules.withdraw.service.IWithdrawRecordService;
import org.jeecg.common.modules.withdraw.vo.WithDrawReqVo;
import org.jeecg.common.util.AmountUtils;
import org.jeecg.common.util.DySmsEnum;
import org.jeecg.common.util.DySmsHelper;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.enums.AccountFlowTypeEnum;
import org.jeecg.common.util.enums.DoctorAccountFlowStatusEnum;
import org.jeecg.common.util.enums.WithdrawRecordStatusEnum;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @Description: withdraw_record
 * @Author: jeecg-boot
 * @Date:   2020-08-22
 * @Version: V1.0
 */
@Slf4j
@Service
public class WithdrawRecordServiceImpl extends ServiceImpl<WithdrawRecordMapper, WithdrawRecord> implements IWithdrawRecordService {

    @Resource
    private IDoctorAccountFlowService doctorAccountFlowService;
    @Resource
    private IDoctorService doctorService;
    @Resource
    private IDoctorAccountService doctorAccountService;
    @Resource
    private RedisUtil redisUtil;

    @Resource
    private WithdrawRecordMapper withdrawRecordMapper;

    private static final String WITHDRAW_LOCK = "withdraw_lock_%s";

    private static final String AUDIT_LOCK = "audit_lock_%s";

    @Override
    public WithdrawRecord getByFlowId(String flowId) {
        LambdaQueryWrapper<WithdrawRecord> query = Wrappers.lambdaQuery();
        query.eq(WithdrawRecord::getDoctorAccountFlowId,flowId);
        return getOne(query);
    }


    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Result withdraw(String doctorId,String loginUser){
        //【一】医生信息获取
        Doctor doctor = doctorService.getById(doctorId);
        if (Objects.isNull(doctor)){
            return Result.error("未获取到医生信息");
        }

        //【二】医生账户信息获取
        DoctorAccount doctorAccount = doctorAccountService.getByDoctorId(doctorId);
        if (Objects.isNull(doctorAccount)){
            return Result.error("未获取到医生账户信息");
        }
        BigDecimal balance = doctorAccount.getBalance();
        if (Objects.isNull(balance) || balance.compareTo(BigDecimal.ZERO) <= 0){
            return Result.error("医生余额为0,无法发起提现");
        }
        if (!redisUtil.setNx(String.format(WITHDRAW_LOCK, doctorId),doctorId,3)){
            return Result.error("您点的太快了，请休息一下再提交吧");
        }

        //【三】变更医生余额、累计收入 + 新增医生流水
        DoctorAccountFlow withdrawFlow = doctorAccountService.changeBalance(doctorId,balance.negate(),AccountFlowTypeEnum.WITHDRAW,null);

        //【四】新增提现
        BigDecimal taxRatio = AmountUtils.fenToYuan(doctor.getShare());  //医生分成比例
        WithdrawRecord record = new WithdrawRecord();
        record.setDoctorId(doctorId);
        record.setDoctorAccountFlowId(withdrawFlow.getId());
        record.setAmount(balance);
        record.setCreateBy(loginUser);
        record.setCreateTime(new Date());
        record.setStatus(WithdrawRecordStatusEnum.APPLY.getCode());
        record.setTaxRatio(taxRatio);
        record.setTaxFee(record.getAmount().multiply(taxRatio));
        record.setReceipt(record.getAmount().subtract(record.getTaxFee()));
        save(record);

        //【五】变更提现流水表的关联id
        withdrawFlow.setRelationId(record.getId());  //设置关系id为提现表id
        doctorAccountFlowService.updateById(withdrawFlow);

        return Result.ok();
    }


    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public Result audit(WithdrawRecordStatusEnum statusEnum, String loginUser, String reason, String id){
        WithdrawRecord exists = getById(id);
        if (Objects.isNull(exists)){
            return new Result().error500("未获取到提现信息，请刷新页面后重试");
        }
        if (!Objects.equals(exists.getStatus(),WithdrawRecordStatusEnum.APPLY.getCode())){
            return new Result().error500("状态已变更，请刷新页面后重试");
        }
        if (Objects.equals(statusEnum,WithdrawRecordStatusEnum.APPLY)){
            return new Result().error500("状态没有变更");
        }
        if (Objects.equals(statusEnum,WithdrawRecordStatusEnum.REFUND) && StringUtils.isBlank(reason)){
            return new Result().error500("请填写拒绝原因");
        }
        DoctorAccountFlow doctorAccountFlow = doctorAccountFlowService.getById(exists.getDoctorAccountFlowId());
        if (Objects.isNull(doctorAccountFlow)){
            return new Result().error500("未获取到医生流水信息，请联系相关技术人员");
        }
        if (!Objects.equals(doctorAccountFlow.getFlowType(),AccountFlowTypeEnum.WITHDRAW.getCode())){
            return new Result().error500("医生流水信息不是提现，请联系相关技术人员核查");
        }
        if (!redisUtil.setNx(String.format(AUDIT_LOCK, id),id,3)){
            return Result.error("您点的太快了，请休息一下再提交吧");
        }
        exists.setStatus(statusEnum.getCode());
        exists.setReason(reason);
        exists.setUpdateBy(loginUser);
        exists.setUpdateTime(new Date());

        doctorAccountFlow.setStatus(DoctorAccountFlowStatusEnum.getInstance(statusEnum).getCode());
        doctorAccountFlowService.updateById(doctorAccountFlow);
        Doctor doctor = doctorService.getById(exists.getDoctorId());
        BigDecimal taxRatio = AmountUtils.fenToYuan(doctor.getShare());
        exists.setTaxRatio(taxRatio);
        exists.setTaxFee(exists.getAmount().multiply(taxRatio));
        updateById(exists);
        if (Objects.equals(statusEnum,WithdrawRecordStatusEnum.REFUND)){
            doctorAccountService.changeBalanceOnly(doctor.getId(),doctorAccountFlow.getAmount().abs());
        }
        try {
            if (Objects.equals(statusEnum,WithdrawRecordStatusEnum.AGREE)){
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("amout",exists.getAmount().toPlainString());
                jsonObject.put("receipt",exists.getReceipt().toPlainString());
                jsonObject.put("tax",exists.getTaxFee().toPlainString());
                DySmsHelper.sendSms(doctor.getMobile(),jsonObject, DySmsEnum.WITHDRAW_SUCCESS);
            }
        } catch (ClientException e) {
            return Result.error("提现发起成功，短信发送失败");
        }
        return Result.ok();
    }

    @Override
    public List<WithDrawReqVo> getWithDrawInfo(String doctorName, String mobile, Integer dataStart, Integer pageSize){
        return withdrawRecordMapper.selectWithDrawInfo(doctorName,mobile,dataStart,pageSize);
    }

    @Override
    public int getWithDrawCount(String doctorName, String mobile){
        return withdrawRecordMapper.getWithDrawCount(doctorName,mobile);
    }

    @Override
    public int getAccountDrawStateCount( String accountId){
        return withdrawRecordMapper.getAccountDrawStateCount(accountId);
    }
}
